package com.ecoolex.cms.system.core.manager;

import java.time.Instant;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.ecoolex.cms.system.core.dao.VRSceneHotspotDAO;
import com.ecoolex.cms.system.entity.VRScene;
import com.ecoolex.cms.system.entity.VRSceneHotspot;
import com.ecoolex.cms.system.entity.VRSceneHotspot.Column;
import com.ecoolex.cms.system.enums.VRSceneStatus;
import com.ecoolex.cms.system.entity.VRSceneHotspotExample;
import com.ecoolex.cms.system.entity.VRSceneHotspotParam;
import com.ecoolex.framework.common.pojo.Page;
import com.ecoolex.framework.common.pojo.Pagination;
import com.ecoolex.framework.common.util.BeanUtil;
import com.ecoolex.framework.common.util.Check;
import com.ecoolex.framework.common.util.MessageFormatter;
import com.ecoolex.framework.modularize.api.service.cache.CacheService;

@Service
public class VRSceneHotspotManager {
	@Autowired
	private VRSceneHotspotDAO dao;
	@Autowired
	private CacheService cacheService;
	@Autowired
	private VRSceneHotspotParamManager vrSceneHotspotParamManager;
	@Autowired
	private VRSceneManager vrSceneManager;

	public Pagination<VRSceneHotspot> query(Integer sceneId, String hotspotName, Page page) {
		VRSceneHotspotExample example = new VRSceneHotspotExample();
		VRSceneHotspotExample.Criteria criteria = example.createCriteria();

		criteria.andSceneIdEqualTo(sceneId).andDeletedEqualTo(VRSceneHotspot.NOT_DELETED);
		if (Check.notNullOrTrimEmpty(hotspotName)) {
			criteria.andHotspotNameLike('%' + hotspotName + '%');
		}

		long totalCount = dao.countByExample(example);

		List<VRSceneHotspot> list = dao.selectByExample(example);

		return Pagination.create(page, totalCount, list);
	}

	public List<VRSceneHotspot> queryBySceneId(Integer sceneId) {
		VRSceneHotspotExample example = new VRSceneHotspotExample();
		example.createCriteria().andSceneIdEqualTo(sceneId).andDeletedEqualTo(VRSceneHotspot.NOT_DELETED);
		return dao.selectByExample(example);
	}

	public VRSceneHotspot getById(Integer hotspotId) {
		VRSceneHotspotExample example = new VRSceneHotspotExample();
		example.createCriteria().andHotspotIdEqualTo(hotspotId).andDeletedEqualTo(VRSceneHotspot.NOT_DELETED);
		return dao.selectOneByExample(example);
	}

	public Boolean online(VRScene scene, String updateUser) {
		queryBySceneId(scene.getSceneId()).forEach(hotspot -> {
			cacheService.put(buildCacheKey(hotspot), buildCacheValue(hotspot));
		});
		return true;
	}

	public Boolean offline(VRScene scene, String updateUser) {
		queryBySceneId(scene.getSceneId()).forEach(hotspot -> {
			cacheService.remove(buildCacheKey(hotspot));
		});
		return true;
	}

	private void needUpdateCache(VRSceneHotspot hotspot) {
		VRScene scene = vrSceneManager.getById(hotspot.getSceneId());
		if (Check.notNull(scene) && scene.getStatus().equals(VRSceneStatus.ONLINE.real())) {
			cacheService.put(buildCacheKey(hotspot), buildCacheValue(hotspot));
		}
	}

	private String buildCacheKey(VRSceneHotspot hotspot) {
		return MessageFormatter.arrayFormat("/cms/vr/scene/hotspot/{}", hotspot.getOpenId());
	}

	private String buildCacheValue(VRSceneHotspot hotspot) {
		JSONObject json = new JSONObject();
		json.put("openId", hotspot.getOpenId());
		json.put("actionType", hotspot.getActionType());
		json.put("actionValue", hotspot.getActionValue());

		json.put("paramList", vrSceneHotspotParamManager.queryByHotspot(hotspot.getHotspotId()).stream().map(param -> {
			JSONObject p = new JSONObject();
			p.put("paramKey", param.getParamKey());
			p.put("paramValue", param.getParamValue());
			return p;
		}).collect(Collectors.toList()));
		return json.toJSONString();
	}

	public Boolean deleteAllBySceneId(Integer sceneId, String updateUser) {
		VRSceneHotspot record = new VRSceneHotspot();
		record.setDeleted(VRSceneHotspot.IS_DELETED);
		record.setUpdateUser(updateUser);
		record.setUpdateTime(Date.from(Instant.now()));

		VRSceneHotspotExample example = new VRSceneHotspotExample();
		example.createCriteria().andSceneIdEqualTo(sceneId).andDeletedEqualTo(VRSceneHotspot.NOT_DELETED);

		dao.updateByExampleSelective(record, example, Column.deleted, Column.updateUser, Column.updateTime);
		return true;
	}

	public Boolean deleteById(Integer hotspotId, String updateUser) {
		VRSceneHotspot record = new VRSceneHotspot();
		record.setHotspotId(hotspotId);
		record.setDeleted(VRSceneHotspot.IS_DELETED);
		record.setUpdateUser(updateUser);
		record.setUpdateTime(Date.from(Instant.now()));
		dao.updateByPrimaryKeySelective(record, Column.deleted, Column.updateUser, Column.updateTime);
		return true;
	}

	@Transactional
	public VRSceneHotspot add(VRSceneHotspot record, List<VRSceneHotspotParam> paramList, String createUser) {
		record.setOpenId(UUID.randomUUID().toString());
		record.setDeleted(VRSceneHotspot.NOT_DELETED);
		record.setCreateUser(createUser);
		record.setCreateTime(Date.from(Instant.now()));
		record.setUpdateUser(createUser);
		record.setUpdateTime(Date.from(Instant.now()));
		dao.insert(record);

		vrSceneHotspotParamManager.add(record, paramList, createUser);

		needUpdateCache(record);

		return record;
	}

	@Transactional
	public VRSceneHotspot edit(VRSceneHotspot record, List<VRSceneHotspotParam> paramList, String updateUser) {
		VRSceneHotspot old = getById(record.getHotspotId());
		old.setUpdateUser(updateUser);
		old.setUpdateTime(Date.from(Instant.now()));

		BeanUtil.copy(record, old, "hotspotId", "sceneId", "sceneId", "openId", "deleted", "createUser", "createTime",
				"updateUser", "updateTime");

		dao.updateByPrimaryKey(old);

		vrSceneHotspotParamManager.edit(old, paramList, updateUser);

		needUpdateCache(old);

		return old;
	}
}